#include <iostream>
using namespace std;

class PaymentStrategy {
public:
	virtual ~PaymentStrategy() {}
	virtual void payoff()=0;
};

class DefaultStrategy: public PaymentStrategy {
public:
	void payoff() {
		cout << "the payoff formula: amount = price * quantity" << endl;
	}
};

class DiscountStrategy: public PaymentStrategy {
public:
	void payoff() {
		cout << "the payoff formula: amount = price * quantity * discount" << endl;
	}
};

class VipStrategy: public PaymentStrategy {
public:
	void payoff() {
		cout << "the payoff formula: amount = price * quantity * vip_discount" << endl;
	}
	void discount() {
		cout << "discount for the vip customer" << endl;
	}
};

class MixStrategy: public PaymentStrategy {
private:
	DiscountStrategy* discountStrategy;
	VipStrategy* vipStrategy;

public:
	MixStrategy(DiscountStrategy* discountStrategy, VipStrategy* vipStrategy) {
		this->discountStrategy = discountStrategy;
		this->vipStrategy = vipStrategy;
	}
	void payoff() {
		discountStrategy->payoff();
		vipStrategy->discount();
	}
};

class Client {
private:
	PaymentStrategy* strategy;
public:
	Client(PaymentStrategy* strategy) {
		this->strategy = strategy;
	}
	void payoff() {
		this->strategy->payoff();
	}
};

class StrategyFactory
{
private:
	StrategyFactory();
public:
	static StrategyFactory* getInstance()
	{
		static StrategyFactory* instance;
		return instance;
	}
	PaymentStrategy* create(string name)
	{
		if (name=="default") return new DefaultStrategy();
		else if (name=="discount") return new DiscountStrategy();
		else if (name=="vip") return new VipStrategy();
		else if (name=="mix") return new MixStrategy(new DiscountStrategy, new VipStrategy);
		else return NULL;
	}
};

int main() 
{
	StrategyFactory* factory = StrategyFactory::getInstance();
	Client* client;

	cout << ">>> the normal payoff:" << endl;
	client = new Client(factory->create("default"));
	client->payoff();

	cout << ">>> the discount payoff:" << endl;
	client = new Client(factory->create("discount"));
	client->payoff();

	cout << ">>> the vip discount payoff:" << endl;
	client = new Client(factory->create("vip"));
	client->payoff();

	cout << ">>> the mix discount payoff:" << endl;
	client = new Client(factory->create("mix"));
	client->payoff();
	return 0;
}
